1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package groovy.json.internal;
20
21 import java.math.BigDecimal;
22
23 import static groovy.json.internal.Exceptions.die;
24 import static groovy.json.internal.Exceptions.handle;
25
26
27
28
29 public class CharScanner {
30
31 protected static final int COMMA = ',';
32 protected static final int CLOSED_CURLY = '}';
33 protected static final int CLOSED_BRACKET = ']';
34 protected static final int LETTER_E = 'e';
35 protected static final int LETTER_BIG_E = 'E';
36 protected static final int DECIMAL_POINT = '.';
37 protected static final int ALPHA_0 = '0';
38 protected static final int ALPHA_1 = '1';
39 protected static final int ALPHA_2 = '2';
40 protected static final int ALPHA_3 = '3';
41 protected static final int ALPHA_4 = '4';
42 protected static final int ALPHA_5 = '5';
43 protected static final int ALPHA_6 = '6';
44 protected static final int ALPHA_7 = '7';
45 protected static final int ALPHA_8 = '8';
46 protected static final int ALPHA_9 = '9';
47 protected static final int MINUS = '-';
48 protected static final int PLUS = '+';
49 protected static final int DOUBLE_QUOTE = '"';
50 protected static final int ESCAPE = '\\';
51
52 static final String MIN_LONG_STR_NO_SIGN = String.valueOf(Long.MIN_VALUE);
53 static final String MAX_LONG_STR = String.valueOf(Long.MAX_VALUE);
54 static final String MIN_INT_STR_NO_SIGN = String.valueOf(Integer.MIN_VALUE);
55 static final String MAX_INT_STR = String.valueOf(Integer.MAX_VALUE);
56
57 private static double powersOf10[] = {
58 1.0,
59 10.0,
60 100.0,
61 1000.0,
62 10000.0,
63 100000.0,
64 1000000.0,
65 10000000.0,
66 100000000.0,
67 1000000000.0,
68 10000000000.0,
69 100000000000.0,
70 1000000000000.0,
71 10000000000000.0,
72 100000000000000.0,
73 1000000000000000.0,
74 10000000000000000.0,
75 100000000000000000.0,
76 1000000000000000000.0,
77 };
78
79 public static boolean isDigit(int c) {
80 return c >= ALPHA_0 && c <= ALPHA_9;
81 }
82
83 public static boolean isDecimalDigit(int c) {
84 return isDigit(c) || isDecimalChar(c);
85 }
86
87 public static boolean isDecimalChar(int currentChar) {
88 switch (currentChar) {
89 case MINUS:
90 case PLUS:
91 case LETTER_E:
92 case LETTER_BIG_E:
93 case DECIMAL_POINT:
94 return true;
95 }
96 return false;
97 }
98
99 public static boolean hasDecimalChar(char[] chars, boolean negative) {
100 int index = 0;
101
102 if (negative) index++;
103
104 for (; index < chars.length; index++) {
105 switch (chars[index]) {
106 case MINUS:
107 case PLUS:
108 case LETTER_E:
109 case LETTER_BIG_E:
110 case DECIMAL_POINT:
111 return true;
112 }
113 }
114 return false;
115 }
116
117 public static boolean isDigits(final char[] inputArray) {
118 for (int index = 0; index < inputArray.length; index++) {
119 char a = inputArray[index];
120 if (!isDigit(a)) {
121 return false;
122 }
123 }
124 return true;
125 }
126
127 public static char[][] splitExact(final char[] inputArray,
128 final char split, final int resultsArrayLength) {
129
130 char[][] results = new char[resultsArrayLength][];
131
132 int resultIndex = 0;
133 int startCurrentLineIndex = 0;
134 int currentLineLength = 1;
135
136
137 char c = '\u0000';
138 int index = 0;
139
140 for (; index < inputArray.length; index++, currentLineLength++) {
141 c = inputArray[index];
142 if (c == split) {
143
144 results[resultIndex] = Chr.copy(
145 inputArray, startCurrentLineIndex, currentLineLength - 1);
146 startCurrentLineIndex = index + 1;
147
148 currentLineLength = 0;
149 resultIndex++;
150 }
151 }
152
153 if (c != split) {
154 results[resultIndex] = Chr.copy(
155 inputArray, startCurrentLineIndex, currentLineLength - 1);
156 resultIndex++;
157 }
158
159 int actualLength = resultIndex;
160 if (actualLength < resultsArrayLength) {
161 final int newSize = resultsArrayLength - actualLength;
162 results = __shrink(results, newSize);
163 }
164 return results;
165 }
166
167 public static char[][] splitExact(final char[] inputArray,
168 final int resultsArrayLength, char... delims) {
169
170 char[][] results = new char[resultsArrayLength][];
171
172 int resultIndex = 0;
173 int startCurrentLineIndex = 0;
174 int currentLineLength = 1;
175
176 char c = '\u0000';
177 int index = 0;
178 int j;
179 char split;
180
181 for (; index < inputArray.length; index++, currentLineLength++) {
182 c = inputArray[index];
183
184 inner:
185 for (j = 0; j < delims.length; j++) {
186 split = delims[j];
187
188 if (c == split) {
189 results[resultIndex] = Chr.copy(
190 inputArray, startCurrentLineIndex, currentLineLength - 1);
191 startCurrentLineIndex = index + 1;
192
193 currentLineLength = 0;
194 resultIndex++;
195 break inner;
196 }
197 }
198 }
199
200 if (!Chr.in(c, delims)) {
201 results[resultIndex] = Chr.copy(
202 inputArray, startCurrentLineIndex, currentLineLength - 1);
203 resultIndex++;
204 }
205
206 int actualLength = resultIndex;
207 if (actualLength < resultsArrayLength) {
208 final int newSize = resultsArrayLength - actualLength;
209 results = __shrink(results, newSize);
210 }
211 return results;
212 }
213
214 public static char[][] split(final char[] inputArray,
215 final char split) {
216
217 char[][] results = new char[16][];
218
219 int resultIndex = 0;
220 int startCurrentLineIndex = 0;
221 int currentLineLength = 1;
222
223 char c = '\u0000';
224 int index = 0;
225
226 for (; index < inputArray.length; index++, currentLineLength++) {
227 c = inputArray[index];
228 if (c == split) {
229 if (resultIndex == results.length) {
230 results = _grow(results);
231 }
232
233 results[resultIndex] = Chr.copy(
234 inputArray, startCurrentLineIndex, currentLineLength - 1);
235 startCurrentLineIndex = index + 1;
236
237 currentLineLength = 0;
238 resultIndex++;
239 }
240 }
241
242 if (c != split) {
243 results[resultIndex] = Chr.copy(
244 inputArray, startCurrentLineIndex, currentLineLength - 1);
245 resultIndex++;
246 }
247
248 int actualLength = resultIndex;
249 if (actualLength < results.length) {
250 final int newSize = results.length - actualLength;
251 results = __shrink(results, newSize);
252 }
253 return results;
254 }
255
256 public static char[][] splitByChars(final char[] inputArray,
257 final char... delims) {
258
259 char[][] results = new char[16][];
260
261 int resultIndex = 0;
262 int startCurrentLineIndex = 0;
263 int currentLineLength = 1;
264
265 char c = '\u0000';
266 int index = 0;
267 int j;
268 char split;
269
270 for (; index < inputArray.length; index++, currentLineLength++) {
271 c = inputArray[index];
272
273 inner:
274 for (j = 0; j < delims.length; j++) {
275 split = delims[j];
276 if (c == split) {
277 if (resultIndex == results.length) {
278 results = _grow(results);
279 }
280
281 results[resultIndex] = Chr.copy(
282 inputArray, startCurrentLineIndex, currentLineLength - 1);
283 startCurrentLineIndex = index + 1;
284
285 currentLineLength = 0;
286 resultIndex++;
287 break inner;
288 }
289 }
290 }
291
292 if (!Chr.in(c, delims)) {
293 results[resultIndex] = Chr.copy(
294 inputArray, startCurrentLineIndex, currentLineLength - 1);
295 resultIndex++;
296 }
297
298 int actualLength = resultIndex;
299 if (actualLength < results.length) {
300 final int newSize = results.length - actualLength;
301 results = __shrink(results, newSize);
302 }
303 return results;
304 }
305
306 public static char[][] splitByCharsFromToDelims(final char[] inputArray, int from, int to,
307 final char... delims) {
308
309 char[][] results = new char[16][];
310
311 final int length = to - from;
312
313 int resultIndex = 0;
314 int startCurrentLineIndex = 0;
315 int currentLineLength = 1;
316
317 char c = '\u0000';
318 int index = from;
319 int j;
320 char split;
321
322 for (; index < length; index++, currentLineLength++) {
323 c = inputArray[index];
324
325 inner:
326 for (j = 0; j < delims.length; j++) {
327 split = delims[j];
328 if (c == split) {
329 if (resultIndex == results.length) {
330 results = _grow(results);
331 }
332
333 results[resultIndex] = Chr.copy(
334 inputArray, startCurrentLineIndex, currentLineLength - 1);
335 startCurrentLineIndex = index + 1;
336
337 currentLineLength = 0;
338 resultIndex++;
339 break inner;
340 }
341 }
342 }
343
344 if (!Chr.in(c, delims)) {
345 results[resultIndex] = Chr.copy(
346 inputArray, startCurrentLineIndex, currentLineLength - 1);
347 resultIndex++;
348 }
349
350 int actualLength = resultIndex;
351 if (actualLength < results.length) {
352 final int newSize = results.length - actualLength;
353 results = __shrink(results, newSize);
354 }
355 return results;
356 }
357
358 public static char[][] splitByCharsNoneEmpty(final char[] inputArray,
359 final char... delims) {
360
361 final char[][] results = splitByChars(inputArray, delims);
362 return compact(results);
363 }
364
365 public static char[][] splitByCharsNoneEmpty(final char[] inputArray, int from, int to,
366 final char... delims) {
367
368 final char[][] results = splitByCharsFromToDelims(inputArray, from, to, delims);
369 return compact(results);
370 }
371
372 public static char[][] compact(char[][] array) {
373 int nullCount = 0;
374 for (char[] ch : array) {
375 if (ch == null || ch.length == 0) {
376 nullCount++;
377 }
378 }
379 char[][] newArray = new char[array.length - nullCount][];
380
381 int j = 0;
382 for (char[] ch : array) {
383 if (ch == null || ch.length == 0) {
384 continue;
385 }
386
387 newArray[j] = ch;
388 j++;
389 }
390 return newArray;
391 }
392
393 private static char[][] _grow(char[][] array) {
394 char[][] newArray = new char[array.length * 2][];
395 System.arraycopy(array, 0, newArray, 0, array.length);
396 return newArray;
397 }
398
399 private static char[][] __shrink(char[][] array, int size) {
400 char[][] newArray = new char[array.length - size][];
401 System.arraycopy(array, 0, (char[][]) newArray, 0, array.length - size);
402 return newArray;
403 }
404
405 public static boolean isLong(char[] digitChars) {
406 return isLong(digitChars, 0, digitChars.length);
407 }
408
409 public static boolean isLong(char[] digitChars, int offset, int len) {
410 String cmpStr = digitChars[offset] == '-' ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR;
411 int cmpLen = cmpStr.length();
412 if (len < cmpLen) return true;
413 if (len > cmpLen) return false;
414
415 for (int i = 0; i < cmpLen; ++i) {
416 int diff = digitChars[offset + i] - cmpStr.charAt(i);
417 if (diff != 0) {
418 return (diff < 0);
419 }
420 }
421 return true;
422 }
423
424 public static boolean isInteger(char[] digitChars) {
425 return isInteger(digitChars, 0, digitChars.length);
426 }
427
428 public static boolean isInteger(char[] digitChars, int offset, int len) {
429 String cmpStr = (digitChars[offset] == '-') ? MIN_INT_STR_NO_SIGN : MAX_INT_STR;
430 int cmpLen = cmpStr.length();
431 if (len < cmpLen) return true;
432 if (len > cmpLen) return false;
433
434 for (int i = 0; i < cmpLen; ++i) {
435 int diff = digitChars[offset + i] - cmpStr.charAt(i);
436 if (diff != 0) {
437 return (diff < 0);
438 }
439 }
440 return true;
441 }
442
443 public static int parseInt(char[] digitChars) {
444 return parseIntFromTo(digitChars, 0, digitChars.length);
445 }
446
447 public static int parseIntFromTo(char[] digitChars, int offset, int to) {
448 try {
449 int num;
450 boolean negative = false;
451 char c = digitChars[offset];
452 if (c == '-') {
453 offset++;
454 negative = true;
455 }
456 if (negative) {
457 num = (digitChars[offset] - '0');
458 if (++offset < to) {
459 num = (num * 10) + (digitChars[offset] - '0');
460 if (++offset < to) {
461 num = (num * 10) + (digitChars[offset] - '0');
462 if (++offset < to) {
463 num = (num * 10) + (digitChars[offset] - '0');
464 if (++offset < to) {
465 num = (num * 10) + (digitChars[offset] - '0');
466 if (++offset < to) {
467 num = (num * 10) + (digitChars[offset] - '0');
468 if (++offset < to) {
469 num = (num * 10) + (digitChars[offset] - '0');
470 if (++offset < to) {
471 num = (num * 10) + (digitChars[offset] - '0');
472 if (++offset < to) {
473 num = (num * 10) + (digitChars[offset] - '0');
474 if (++offset < to) {
475 num = (num * 10) + (digitChars[offset] - '0');
476 }
477 }
478 }
479 }
480 }
481 }
482 }
483 }
484 }
485 } else {
486 num = (digitChars[offset] - '0');
487 if (++offset < to) {
488 num = (num * 10) + (digitChars[offset] - '0');
489 if (++offset < to) {
490 num = (num * 10) + (digitChars[offset] - '0');
491 if (++offset < to) {
492 num = (num * 10) + (digitChars[offset] - '0');
493 if (++offset < to) {
494 num = (num * 10) + (digitChars[offset] - '0');
495 if (++offset < to) {
496 num = (num * 10) + (digitChars[offset] - '0');
497 if (++offset < to) {
498 num = (num * 10) + (digitChars[offset] - '0');
499 if (++offset < to) {
500 num = (num * 10) + (digitChars[offset] - '0');
501 if (++offset < to) {
502 num = (num * 10) + (digitChars[offset] - '0');
503 if (++offset < to) {
504 num = (num * 10) + (digitChars[offset] - '0');
505 }
506 }
507 }
508 }
509 }
510 }
511 }
512 }
513 }
514
515 }
516 return negative ? num * -1 : num;
517 } catch (Exception ex) {
518 return handle(int.class, ex);
519 }
520 }
521
522 public static int parseIntFromToIgnoreDot(char[] digitChars, int offset, int to) {
523 int num;
524 boolean negative = false;
525 char c = digitChars[offset];
526 if (c == '-') {
527 offset++;
528 negative = true;
529 }
530
531 c = digitChars[offset];
532 num = (c - '0');
533 offset++;
534
535 for (; offset < to; offset++) {
536 c = digitChars[offset];
537 if (c != '.') {
538 num = (num * 10) + (c - '0');
539 }
540 }
541
542 return negative ? num * -1 : num;
543 }
544
545 public static long parseLongFromToIgnoreDot(char[] digitChars, int offset, int to) {
546 long num;
547 boolean negative = false;
548 char c = digitChars[offset];
549 if (c == '-') {
550 offset++;
551 negative = true;
552 }
553
554 c = digitChars[offset];
555 num = (c - '0');
556 offset++;
557
558 for (; offset < to; offset++) {
559 c = digitChars[offset];
560 if (c != '.') {
561 num = (num * 10) + (c - '0');
562 }
563 }
564
565 return negative ? num * -1 : num;
566 }
567
568 public static long parseLongFromTo(char[] digitChars, int offset, int to) {
569 long num;
570 boolean negative = false;
571 char c = digitChars[offset];
572 if (c == '-') {
573 offset++;
574 negative = true;
575 }
576
577 c = digitChars[offset];
578 num = (c - '0');
579 offset++;
580
581 long digit;
582
583 for (; offset < to; offset++) {
584 c = digitChars[offset];
585 digit = (c - '0');
586 num = (num * 10) + digit;
587 }
588
589 return negative ? num * -1 : num;
590 }
591
592 public static long parseLong(char[] digitChars) {
593 return parseLongFromTo(digitChars, 0, digitChars.length);
594 }
595
596 public static Number parseJsonNumber(char[] buffer) {
597 return parseJsonNumber(buffer, 0, buffer.length);
598 }
599
600 public static Number parseJsonNumber(char[] buffer, int from, int to) {
601 return parseJsonNumber(buffer, from, to, null);
602 }
603
604 public static final boolean isNumberDigit(int c) {
605 return c >= ALPHA_0 && c <= ALPHA_9;
606 }
607
608 protected static boolean isDelimiter(int c) {
609 return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
610 }
611
612 public static Number parseJsonNumber(char[] buffer, int from, int max, int size[]) {
613 Number value = null;
614 boolean simple = true;
615 int digitsPastPoint = 0;
616
617 int index = from;
618
619 if (buffer[index] == '-') {
620 index++;
621 }
622
623 boolean foundDot = false;
624 for (; index < max; index++) {
625 char ch = buffer[index];
626 if (isNumberDigit(ch)) {
627 if (foundDot == true) {
628 digitsPastPoint++;
629 }
630 } else if (ch <= 32 || isDelimiter(ch)) {
631 break;
632 } else if (ch == '.') {
633 if (foundDot) {
634 die("unexpected character " + ch);
635 }
636 foundDot = true;
637 } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
638 simple = false;
639 } else {
640 die("unexpected character " + ch);
641 }
642 }
643
644 if (digitsPastPoint >= powersOf10.length - 1) {
645 simple = false;
646 }
647
648 final int length = index - from;
649
650 if (!foundDot && simple) {
651 if (isInteger(buffer, from, length)) {
652 value = parseIntFromTo(buffer, from, index);
653 } else {
654 value = parseLongFromTo(buffer, from, index);
655 }
656 } else if (foundDot && simple) {
657 BigDecimal lvalue;
658
659 if (length < powersOf10.length) {
660 if (isInteger(buffer, from, length)) {
661 lvalue = new BigDecimal(parseIntFromToIgnoreDot(buffer, from, index));
662 } else {
663 lvalue = new BigDecimal(parseLongFromToIgnoreDot(buffer, from, index));
664 }
665
666 BigDecimal power = new BigDecimal(powersOf10[digitsPastPoint]);
667 value = lvalue.divide(power);
668 } else {
669 value = new BigDecimal(new String(buffer, from, length));
670 }
671 } else {
672 value = new BigDecimal(new String(buffer, from, index - from));
673 }
674
675 if (size != null) {
676 size[0] = index;
677 }
678
679 return value;
680 }
681
682 public static BigDecimal parseBigDecimal(char[] buffer) {
683 return parseBigDecimal(buffer, 0, buffer.length);
684 }
685
686 public static BigDecimal parseBigDecimal(char[] buffer, int from, int to) {
687 return new BigDecimal(parseDouble(buffer, from, to));
688 }
689
690 public static float parseFloat(char[] buffer, int from, int to) {
691 return (float) parseDouble(buffer, from, to);
692 }
693
694 public static double parseDouble(char[] buffer) {
695 return parseDouble(buffer, 0, buffer.length);
696 }
697
698 public static double parseDouble(char[] buffer, int from, int to) {
699 double value;
700 boolean simple = true;
701 int digitsPastPoint = 0;
702
703 int index = from;
704
705 if (buffer[index] == '-') {
706 index++;
707 }
708
709 boolean foundDot = false;
710 for (; index < to; index++) {
711 char ch = buffer[index];
712 if (isNumberDigit(ch)) {
713 if (foundDot == true) {
714 digitsPastPoint++;
715 }
716 } else if (ch == '.') {
717 if (foundDot) {
718 die("unexpected character " + ch);
719 }
720 foundDot = true;
721 } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
722 simple = false;
723 } else {
724 die("unexpected character " + ch);
725 }
726 }
727
728 if (digitsPastPoint >= powersOf10.length - 1) {
729 simple = false;
730 }
731
732 final int length = index - from;
733
734 if (!foundDot && simple) {
735 if (isInteger(buffer, from, length)) {
736 value = parseIntFromTo(buffer, from, index);
737 } else {
738 value = parseLongFromTo(buffer, from, index);
739 }
740 } else if (foundDot && simple) {
741 long lvalue;
742
743 if (length < powersOf10.length) {
744 if (isInteger(buffer, from, length)) {
745 lvalue = parseIntFromToIgnoreDot(buffer, from, index);
746 } else {
747 lvalue = parseLongFromToIgnoreDot(buffer, from, index);
748 }
749
750 double power = powersOf10[digitsPastPoint];
751 value = lvalue / power;
752 } else {
753 value = Double.parseDouble(new String(buffer, from, length));
754 }
755 } else {
756 value = Double.parseDouble(new String(buffer, from, index - from));
757 }
758
759 return value;
760 }
761
762 public static int skipWhiteSpace(char[] array, int index) {
763 int c;
764 for (; index < array.length; index++) {
765 c = array[index];
766 if (c > 32) {
767 return index;
768 }
769 }
770 return index;
771 }
772
773 public static int skipWhiteSpace(char[] array, int index, final int length) {
774 int c;
775 for (; index < length; index++) {
776 c = array[index];
777 if (c > 32) {
778 return index;
779 }
780 }
781 return index;
782 }
783
784 public static char[] readNumber(char[] array, int idx) {
785 final int startIndex = idx;
786
787 while (true) {
788 if (!CharScanner.isDecimalDigit(array[idx])) {
789 break;
790 } else {
791 idx++;
792 if (idx >= array.length) break;
793 }
794 }
795
796 return ArrayUtils.copyRange(array, startIndex, idx);
797 }
798
799 public static char[] readNumber(char[] array, int idx, final int len) {
800 final int startIndex = idx;
801
802 while (true) {
803 if (!CharScanner.isDecimalDigit(array[idx])) {
804 break;
805 } else {
806 idx++;
807 if (idx >= len) break;
808 }
809 }
810
811 return ArrayUtils.copyRange(array, startIndex, idx);
812 }
813
814 public static int skipWhiteSpaceFast(char[] array) {
815 int c;
816 int index = 0;
817 for (; index < array.length; index++) {
818 c = array[index];
819 if (c > 32) {
820 return index;
821 }
822 }
823 return index;
824 }
825
826 public static int skipWhiteSpaceFast(char[] array, int index) {
827 char c;
828 for (; index < array.length; index++) {
829 c = array[index];
830 if (c > 32) {
831 return index;
832 }
833 }
834 return index - 1;
835 }
836
837 public static String errorDetails(String message, char[] array, int index, int ch) {
838 CharBuf buf = CharBuf.create(255);
839
840 buf.addLine(message);
841
842 buf.addLine("");
843 buf.addLine("The current character read is " + debugCharDescription(ch));
844
845 buf.addLine(message);
846
847 int line = 0;
848 int lastLineIndex = 0;
849
850 for (int i = 0; i < index && i < array.length; i++) {
851 if (array[i] == '\n') {
852 line++;
853 lastLineIndex = i + 1;
854 }
855 }
856
857 int count = 0;
858
859 for (int i = lastLineIndex; i < array.length; i++, count++) {
860 if (array[i] == '\n') {
861 break;
862 }
863 }
864
865 buf.addLine("line number " + (line + 1));
866 buf.addLine("index number " + index);
867
868 try {
869 buf.addLine(new String(array, lastLineIndex, count));
870 } catch (Exception ex) {
871 try {
872 int start = index = (index - 10 < 0) ? 0 : index - 10;
873
874 buf.addLine(new String(array, start, index));
875 } catch (Exception ex2) {
876 buf.addLine(new String(array, 0, array.length));
877 }
878 }
879 for (int i = 0; i < (index - lastLineIndex); i++) {
880 buf.add('.');
881 }
882 buf.add('^');
883
884 return buf.toString();
885 }
886
887 public static String debugCharDescription(int c) {
888 String charString;
889 if (c == ' ') {
890 charString = "[SPACE]";
891 } else if (c == '\t') {
892 charString = "[TAB]";
893 } else if (c == '\n') {
894 charString = "[NEWLINE]";
895 } else {
896 charString = "'" + (char) c + "'";
897 }
898
899 charString = charString + " with an int value of " + ((int) c);
900 return charString;
901 }
902 }